<html>
    <head>
        <title>Mutation 突变</title>
    </head>
    <body>
        <script>
            //  Mutation 突变

                    /*
                        一、概述

                                    Vuex 中 store 数据改变的唯一方法就是 mutation 突变。

                                    通俗的理解， mutations 里面装着的是改变状态数据的方法集合，处理数据逻辑的方法全部放在 mutations 里，是数据和视图分离。

                                    Vuex 中的 mutation 非常类似于事件：  每个 mutation 都有一个 "字符串的事件类型 (type)" 和 一个"回调函数 (handler)". 

                    */

                    /*

                        二、如何注册突变

                                    这个回调函数就是我们实际进行状态更改的地方，并且它会接受 state 作为第一个参数：
                                    eg:

                                            // 页面路径：  store/index.js
                                            import Vue  from 'vue'
                                            import Vuex form 'vuex'

                                            Vue.use(Vuex);

                                            const store = new Vuex.Store({
                                                state:{
                                                    count:1
                                                },
                                                mutations:{
                                                    add(state){  // 注册突变方法，add就是突变的类型
                                                        // 变更状态
                                                        state.count += 2;
                                                    }
                                                }
                                            })

                                            export default sotre;


                        */

                        /*
                            三、触发突变

                                    使用 store.

                                    你不能直接调用一个 mutation handler.  
                                    
                                    这个选项更像是事件注册： "当触发一个类型为 add 的 mutation 时，调用此函数"，

                                    要唤醒一个 mutation handler,你需要以相应的 type 调用  store.commit 方法。

                                    注意：   store.commit 调用  mutation (需要在根节点注入 store)


                                    eg:

                                        !-- 页面路径：  pages/index/index.vue --

                                        <template>
                                            <view>
                                                 <view> 数量：{{count}} </view>
                                                 <button @click = 'addCount'> 增加 </button>
                                            </view>
                                        </template>
                                        <script>
                                            import store from '@/store/index.js';
                                            export default {
                                                computed:{
                                                    count(){
                                                        return this.$store.state.count
                                                    }
                                                },
                                                methods:{
                                                    addCount(){
                                                        sotre.commit('add')
                                                    }
                                                }
                                            }
                                        <//script>
                    */

                    /*
                         四、传入参数
                         
                                 你可以向 store.commit 传入额外的参数， 即 mutation 的 载荷 (payload)：

                                      还是以累加器的例子来实现  motation 函数的传参，来冬天定义累加的数量。

                                      1、在注册 mutation 传参(载荷)，可以传递一个参数：

                                                        // 页面路径：  store/index.js

                                                            import Vue from 'vue'
                                                            import Vuex from 'vuex'

                                                            Vue.use(Vuex);

                                                            const store = new  Vuex.Store({
                                                                state:{
                                                                    count:1
                                                                },
                                                                mutations:{
                                                                    add(state,n){ // 注册突变时，规定传入参数
                                                                        state..count +=n
                                                                    }
                                                                }
                                                            })

                                                            export defailt store;


                                                        !-- 页面路径 ：  pages/index/index.vue --

                                                        <template>
                                                            <view>
                                                                <view>数量：{{count}}</view>
                                                            </vie>
                                                        </template>

                                                        <script>
                                                            import store from  '@/store/index.js'
                                                            export default{
                                                                computed:{
                                                                    count(){
                                                                        return this.$store.state.count
                                                                    }
                                                                },
                                                                methods:{
                                                                    addCount('add',5) // 每次累加5
                                                                }
                                                            }
                                                        <//script>


                                     2、在 mutation 传参 (载荷) 也可以传递一个对象。让我们修改上面累加器的例子：

                                            // 页面路径 :  store/index.js

                                            import Vue from 'vue'
                                            import Vuex from 'vuex'

                                            Vue.use(Vuex);

                                            const store = new  Vuex.Store({
                                                state:{
                                                     count:1
                                                },
                                                mutations:{
                                                    add(state,payload){
                                                        state.count += payload.amount
                                                    }
                                                }
                                            })

                                            export default store;


                                            ！-- 页面路径 : pages/index/index.vue --

                                            <template>
                                                <view>
                                                    <view>数量: {{count}} </view>
                                                    <button @click ='addCount'>增加</button>
                                                </view>
                                            </template>
                                            <script>
                                                import store from '@/store/index.js'
                                                export default{
                                                    computed:{
                                                        count(){
                                                            return this.$store.state.count
                                                        }
                                                    },
                                                    methods:{
                                                        addCount(){ // 把载荷 和 type 分开提交
                                                            store.commit('add',{amount:10})
                                                        }
                                                    }
                                                }
                                            <//script>

                    */

                    /*
                            五、提交方式

                                    1、对象风格的提交方式

                                                我们修改组件中 store.commit 提交方式：

                                                !-- 页面路径：  pages/index/index.vue ---

                                                <template>
                                                    <view>
                                                        <view>数量： {{count}} </view>
                                                        <button @click ="addCount">增加</button>
                                                    </view>
                                                </template>
                                                <script>
                                                    import store from '@/store/index.js'
                                                    export default{
                                                        computed:{
                                                            count(){
                                                                return this.$store.state.count
                                                            }
                                                        },
                                                        methods:{
                                                            addCount(){ // 整个对象都作为载荷传给 mutation 函数
                                                                store.commit({
                                                                    type:'add',
                                                                    amount:6
                                                                })
                                                            }
                                                        }
                                                    }
                                                <//script>

                                        当使用对象风格的提交方式，整个对象都作为载荷传给 mutation 函数，因此  handler 保持不变：

                                                mutations:{
                                                    add(state,payload){
                                                        state.count += payload.amount
                                                    }
                                                }


                                 2、mapMutations 辅助函数

                                        通过mapMutations 辅助函数提交。

                                        创建组件方法提交 mutation。

                                        使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。

                                        eg:

                                                !--- 页面路径：  pages/index/index.vue ---

                                                <template>
                                                    <view>
                                                        <view>数量： {{ count}} </view>
                                                        <button @click="add">增加</button>
                                                    </view>
                                                </template>

                                                <script>
                                                    import {mapMutations} from 'vuex' // 引入辅助函数
                                                    export default{
                                                        computed:{
                                                            count(){
                                                                return this.$store.state.count
                                                            }
                                                        },
                                                        methods:{
                                                            ...mapMutations(["add"]) // 将 add 方法映射为 this.add()
                                                        }
                                                    }
                                                <//script>

                                                !-- 页面路径： store/index.js ---
                                                import Vue from 'vue'
                                                import Vuex from 'vuex'

                                                VUe.use(Vuex);

                                                const store = new Vuex.Store({
                                                    state:{
                                                        count:1
                                                    },
                                                    mutations:{
                                                        add(state){
                                                            // 变更状态
                                                            state.count +=2
                                                        }
                                                    }
                                                })

                                                export default store
                    */

                    /*
                          六、需要遵守的规则
                          
                                    既然 Vuex 的  store 中的状态是响应式的，那么当我们变更状态时，监视状态的 Vue 组件也会自动更新。

                                    这也意味着  Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项：

                                       1、最好提前在你的  store 中初始化好所有所需属性。

                                       2、当需要在对象上添加新属性时，你应该

                                                ①、使用 Vue.set(object,'newProp',123),

                                                ②、或者，一新对象替换老对象。例如，利用对象展开运算符我们可以这样写：
                                                    
                                                    state.obj ={ ...state.obj,newProp:123}

                                    ★、Mutation 必须是同步函数

                                               一条重要的原则就是要记住** mutation 必须是同步函数**
                                               
                                               我们要通过 "提交mutation" 的方式来改变状态数据，是因为我们想要更明确地追踪到状态的变化。

                                               如果是类似下面这样异步的话：

                                                  	mutations: {
                                                        someMutation (state) {
                                                            api.callAsyncMethod(() => {
                                                                state.count++
                                                            })
                                                        }
                                                    }

                                              我们就不知道什么时候状态发生变化，所以也就无法追踪了，这与  mutation 的设计初心相孛，所以强制规定它必须是同步函数。
                    */
        </script>
    </body>
</html>